package com.easybuilder.common.utils;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class ThreadPoolUtil {

    /** cpu核心数 */
    private static int coreSize;

    static {
        coreSize = Runtime.getRuntime().availableProcessors();
    }

    /** 通过静态枚举实现单例线程池 */
    static enum singleton {
        INSTANCE;
        private ThreadPoolExecutor executor;
        // 私有构造
        private singleton (){
            int corePoolSize = coreSize * 2 + 1;
            executor = new ThreadPoolExecutor(corePoolSize, corePoolSize + 10, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new SingletonThreadFactory(), new RejectHandler());
            log.info("单例线程池初始化完成，cpu核心数：{}, corePoolSize:{}...............", coreSize, corePoolSize);
        }
        public ThreadPoolExecutor getInstance(){
            return executor;
        }
    }

    /** 自定义线程工厂 */
    static class SingletonThreadFactory implements ThreadFactory {
        // 标识
        private final AtomicInteger index = new AtomicInteger(0);

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(new ThreadGroup("SingtonGroup"), r);
            for (;;) {
                int current = index.get();
                int next = current + 1;
                if (index.compareAndSet(current, next)) {
                    t.setName("single-pool-" + next);
                    break;
                }
            }
            return t;
        }
    }

    /** 自定义拒绝策略 */
    static class RejectHandler implements RejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            log.info("单例线程池触发拒绝策略，使用调用者线程执行");
            r.run();
        }
    }

    /** 获取单例线程池 */
    public static ThreadPoolExecutor getExecutor(){
        return singleton.INSTANCE.getInstance();
    }

    /** 关闭线程池 */
    public static void shutdown(ExecutorService executor) {
        executor.shutdown();
        try {
            executor.awaitTermination(100, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
